package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.PingPPConstant;
import cn.huiyunche.base.service.enums.PayTypeEnum;
import cn.huiyunche.base.service.enums.PaymentStatusEnum;
import cn.huiyunche.base.service.enums.PingPPChannelEnum;
import cn.huiyunche.base.service.framework.utils.HYCUtils;
import cn.huiyunche.base.service.framework.utils.HttpUtils;
import cn.huiyunche.base.service.framework.utils.WebVerifyUtils;
import cn.huiyunche.base.service.interfaces.*;
import cn.huiyunche.base.service.mappers.SOrderPaymentMapper;
import cn.huiyunche.base.service.mappers.ext.SOrderPaymentViewMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.vo.*;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.*;
import com.pingplusplus.model.Charge;
import com.pingplusplus.model.Event;
import com.pingplusplus.model.Webhooks;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.util.*;

@Service

public class PaymentmentServiceImpl implements PaymentmentService {

    private static final Logger logger = LoggerFactory.getLogger(PaymentmentServiceImpl.class);

    @Autowired
    private SOrderPaymentMapper sOrderPaymentMapper = null;

    @Autowired
    private SOrderPaymentViewMapper sOrderPaymentViewMapper = null;

    @Autowired
    private SOrderService orderService = null;

    @Autowired
    private UserService userService = null;

    @Autowired
    private OrderStatusLogService orderStatusLogService = null;

    @Autowired
    private UserDeviceService userDeviceService = null;

    @Autowired
    private BScoresTurnoverService bScoresTurnoverService = null;

    @Autowired
    private BScoresService bScoresService = null;

    private BScoresService getBScoresService() {
        return this.bScoresService;
    }

    private BScoresTurnoverService getBScoresTurnoverService() {
        return this.bScoresTurnoverService;
    }

    @Override
    public Boolean payfinish(HttpServletRequest request) {
        Boolean blnRtn = false;
        try {
            HashMap<String, String> hashMap = Maps.newHashMap();
            String strSignatureKey = "X-Pingplusplus-Signature";
            //获取头部所有信息
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String key = headerNames.nextElement().toLowerCase();
                String value = request.getHeader(key);
                hashMap.put(key, value);
            }
            String signature = "";
            if (hashMap.containsKey(strSignatureKey.toLowerCase())) {
                signature = hashMap.get(strSignatureKey.toLowerCase());
            }
            // 获得 http body 内容
            BufferedReader reader = request.getReader();
            StringBuffer buffer = new StringBuffer();
            String string;
            while ((string = reader.readLine()) != null) {
                buffer.append(string);
            }
            reader.close();
            // 该数据请从 request 中获取原始 POST 请求数据
            String webhooksRawPostData = buffer.toString();
            blnRtn = WebVerifyUtils.verifyData(webhooksRawPostData, signature, WebVerifyUtils.getPubKey());
            if (blnRtn) {
                // 解析异步通知数据
                Event event = Webhooks.eventParse(buffer.toString());
                //支付成功
                if ("charge.succeeded".equals(event.getType())) {
                    blnRtn = this.writeOrderPayMessage(event);
                    //退款成功
                } else blnRtn = "refund.succeeded".equals(event.getType());
            }
            return blnRtn;
        } catch (Exception e) {
            logger.error("PaymentmentServiceImpl.payfinish error : {}", e);
            e.printStackTrace();
            throw new BusinessException(e);
        }
    }

    /**
     * @param event
     * @return
     * @Title:回写订单数据
     * @Description: 根据webhook回写订单数据
     * @return: Result<Boolean>
     */
    private Boolean writeOrderPayMessage(Event event) {
        logger.info("PaymentmentServiceImpl.writeOrderPayMessage param : {}", event);
        Boolean blnRtn = false;
        try {
            Object obj = Webhooks.getObject(event.toString());
            if (obj instanceof Charge) {
                Charge charge = (Charge) obj;
                Map<String, Object> extraMap = charge.getExtra();

                // 支付回调防重
                SOrderPaymentExample sOrderPaymentExample = new SOrderPaymentExample();
                String payReceipt = charge.getTransactionNo();
                sOrderPaymentExample.createCriteria().andPayReceiptEqualTo(payReceipt);
                List<SOrderPayment> payDetails = this.getSOrderPaymentMapper().selectByExample(sOrderPaymentExample);
                if (payDetails != null && payDetails.size() > 0) {
                    logger.info("订单重复支付.payReceipt:{}.", payReceipt);
                    return true;
                }

                String orderCode = charge.getOrderNo().split("A")[0];
                SOrderExample search = new SOrderExample();
                search.createCriteria().andOrderCodeEqualTo(orderCode);
                List<SOrder> orderLists = this.getOrderService().selectByExample(search);
                if (orderLists != null && orderLists.size() > 0) {
                    SOrder order = orderLists.get(0);
                    if (order != null && charge.getPaid()) {
                        int intRtn = orderService.getPayStatusById(order.getId());
                        // SOrderPayment sOrderPayment = new SOrderPayment();
                        SOrderPaymentExample example = new SOrderPaymentExample();
                        example.createCriteria().andPayAccountEqualTo(charge.getOrderNo());
                        SOrderPayment sOrderPayment = this.getSOrderPaymentMapper().selectByExample(example).get(0);
                        sOrderPayment.setOrderId(order.getId());
                        sOrderPayment.setUserId(order.getUserId());
                        BigDecimal cost = BigDecimal.valueOf(charge.getAmount()).divide(BigDecimal.valueOf(100));
                        sOrderPayment.setActualCost(cost);
                        // paydetail保存chargeId供退款使用
                        sOrderPayment.setChargeId(charge.getId());

                        if (charge.getChannel().equals(PingPPChannelEnum.ALIPAY.getValue())) {
                            sOrderPayment.setPayType(PayTypeEnum.Alpay.getValue());
                            String buyer_account = (String) extraMap.get("buyer_account");
                            sOrderPayment.setPayAccount(buyer_account);
                            sOrderPayment.setPayReceipt(payReceipt);
                        } else if (charge.getChannel().equals(PingPPChannelEnum.WX.getValue()) ||
                                charge.getChannel().equals(PingPPChannelEnum.WX_PUB.getValue())) {
                            sOrderPayment.setPayType(PayTypeEnum.WechatPay.getValue());
                            String openid = (String) extraMap.get("open_id");
                            sOrderPayment.setPayAccount(openid);
                            sOrderPayment.setPayReceipt(payReceipt);
                        }

                        this.getSOrderPaymentMapper().updateByPrimaryKey(sOrderPayment);

                        SUser sUser = this.getUserService().selectByPrimaryKey(order.getUserId());
                        // 调用订单发布的接口
                        UserVo user = new UserVo(order.getUserId(), sUser.getPhone(), null, null, false, null);
                        this.getOrderService().kylePublish(order.getId(), false, user);

                        // 扣除积分
                        this.getBScoresTurnoverService().updateByPaymentId(sOrderPayment.getId());

                        Long userId = order.getUserId();
                        Integer userType = order.getOrderType();
                        BigDecimal actualtotal = sOrderPayment.getActualCost();
                        // 添加用户 积分
                        logger.info("create order add user scores params userId : {}, userType : {}, actualtotal : {}.", userId, userType, actualtotal);
                        int addTotalCost = this.getBScoresService().addTotalCost(order.getId(), userId, order.getOrderType(), actualtotal);
                        logger.info("create order add user scores params userId : {}, userType : {}, actualtotal : {}, count : {}.", userId, userType, actualtotal, addTotalCost);

                        //更新订单的状态
                        if (intRtn == PaymentStatusEnum.UNPAID.getValue()) {
                            orderService.updateOrderPayStatusForRedis(order.getId(), PaymentStatusEnum.ALREADY_PAID.getValue());
                        }
                        blnRtn = true;
                        logger.info("PaymentmentServiceImpl.writeOrderPayMessage return : {}", blnRtn.toString());
                    }
                }

            }
        } catch (Exception e) {
            logger.error("PaymentmentServiceImpl.writeOrderPayMessage error : {}", e);
            e.printStackTrace();
            throw new BusinessException("回写订单异常");
        }
        return blnRtn;
    }
    /*private Boolean writeOrderPayMessage(Event event) {
		LOGGER.info("PaymentmentServiceImpl.writeOrderPayMessage param : {}", event);
		Boolean blnRtn=false;
		try {
			Object obj = Webhooks.getObject(event.toString());
			if (obj instanceof Charge) {
				Charge charge=(Charge)obj;
				Map<String, Object> extraMap=charge.getExtra();		
				// String orderCode=charge.getOrderNo().substring(0,charge.getOrderNo().length()-ORDER_LENGTH);
				String orderCode = charge.getOrderNo().split("A")[0];
				SOrderExample search = new SOrderExample();
				search.createCriteria().andOrderCodeEqualTo(orderCode);
				
				// 支付回调防重
				SOrderPaymentExample sOrderPaymentExample = new SOrderPaymentExample();
				String payReceipt = charge.getTransactionNo();
				sOrderPaymentExample.createCriteria().andPayReceiptEqualTo(payReceipt);
				List<SOrderPayment> payDetails = this.getSOrderPaymentMapper().selectByExample(sOrderPaymentExample);
				if(payDetails != null && payDetails.size() > 0){
					LOGGER.info("订单重复支付.payReceipt:{}.", payReceipt);
					return true;
				}
				
				List<SOrder> orderLists=this.getOrderService().selectByExample(search);
				if(orderLists!=null && orderLists.size()>0){
					SOrder order=orderLists.get(0);
					if(order!=null && charge.getPaid()){
						int intRtn=orderService.getPayStatusById(order.getId());
						// SOrderPayment sOrderPayment = new SOrderPayment();
						SOrderPaymentExample example = new SOrderPaymentExample();
						example.createCriteria().and
						sOrderPayment.setOrderId(order.getId());
						sOrderPayment.setUserId(order.getUserId());
						BigDecimal cost=BigDecimal.valueOf(charge.getAmount()).divide(BigDecimal.valueOf(100));
						sOrderPayment.setActualCost(cost);
						// paydetail保存chargeId供退款使用
						sOrderPayment.setChargeId(charge.getId());
						//判断订单支付状态
						//支付定金
						if(intRtn==PaymentStatusEnum.UNPAID.getValue()){ 
							payDetail.setCostType(CostTypeEnum.PAY_DEPOSIT.getValue());
						}
						//支付尾款
						else if(intRtn==PaymentStatusEnum.PAID_DEPOSIT.getValue()){
							payDetail.setCostType(CostTypeEnum.ALL_PAID.getValue());
						}
						
						if(charge.getChannel().equals(PingPPChannelEnum.ALIPAY.getValue()))
						{
							sOrderPayment.setPayType(PayTypeEnum.Alpay.getValue());
							String buyer_account=(String) extraMap.get("buyer_account");
							sOrderPayment.setPayAccount(buyer_account);
							sOrderPayment.setPayReceipt(payReceipt);
						}
						else if(charge.getChannel().equals(PingPPChannelEnum.WX.getValue())||
								charge.getChannel().equals(PingPPChannelEnum.WX_PUB.getValue()))
						{
							sOrderPayment.setPayType(PayTypeEnum.WechatPay.getValue());
							String openid=(String) extraMap.get("open_id");
							sOrderPayment.setPayAccount(openid);
							sOrderPayment.setPayReceipt(payReceipt);
						}
						
						this.getSOrderPaymentMapper().insertSelective(sOrderPayment);
						
						//更新订单的状态
						if(intRtn==PaymentStatusEnum.UNPAID.getValue()){ 
							orderService.updateOrderPayStatusForRedis(order.getId(), PaymentStatusEnum.ALREADY_PAID.getValue());
						}
						else if(intRtn==PaymentStatusEnum.PAID_DEPOSIT.getValue()){
							orderService.updateOrderPayStatusForRedis(order.getId(),PaymentStatusEnum.ALREADY_PAID.getValue());
						}
						
						// SUser sUser=userService.getById(order.getUserId());
						
						//消息提示
						// if(intRtn==PaymentStatusEnum.UNPAID.getValue()){ 
						// String content = "您的订单"+order.getOrderCode()+"已支付成功.";
						// msgService.add(MessageClassificationEnum.ORDER.getValue(), MessageTypeEnum.CONFIRMCARRIER.getValue(), content, user.getId(), user.getName(), order.getId(), order.getOrderCode());
						// this.getOrderStatusLogService().insertSelective(order.getId(), StatusCategoryEnum.PAY, PaymentStatusEnum.ALREADY_PAID);
						
						// }
						else if(intRtn==PaymentStatusEnum.PAID_DEPOSIT.getValue()){
							String content = "您的订单"+order.getOrderCode()+"已支付尾款";
							msgService.add(MessageClassificationEnum.ORDER.getValue(), MessageTypeEnum.CONFIRMCARRIER.getValue(), content, user.getId(), user.getName(), order.getId(), order.getOrderCode());
						}
						
						blnRtn=true;
						LOGGER.info("PaymentmentServiceImpl.writeOrderPayMessage return : {}", blnRtn.toString());
					}
				}
				
			}
		}
		catch (Exception e) {
			LOGGER.error("PaymentmentServiceImpl.writeOrderPayMessage error : {}", e);
			throw new BusinessException("回写订单异常");
		}
		return blnRtn;
	}*/

    @Override
    public Result<Map<String, Object>> getListByPage(PageVo page) {
        logger.info("PaymentmentServiceImpl.getListByPage patams : {}", page.toString());
        try {
            Result<Map<String, Object>> result = new Result<>(true, "查询成功!");
            Map<String, Object> map = new HashMap<>();
            SOrderPaymentExample search = new SOrderPaymentExample();
            search.createCriteria().andUserIdEqualTo(this.getUserService().getCurrentUserVo().getId()).andChargeIdIsNotNull();
            page.setTotalRecord(this.getSOrderPaymentMapper().countByExample(search));
            if (StringUtils.isNotBlank(page.getOrder())) {
                search.setOrderByClause(page.getOrder());
            } else {
                search.setOrderByClause(" id DESC ");
            }
            search.setLimitStart(page.getStartIndex());
            search.setLimitEnd(page.getPageSize());

            List<SOrderPaymentVo> list = this.getsOrderPaymentViewMapper().selectDetailList(search);
            if (CollectionUtils.isNotEmpty(list)) {
                for (int i = 0; i < list.size(); i++) {
                    SOrderPaymentVo vo = list.get(i);
                    vo.setCostText("支付订单");
                    vo.setCostType(0);
                }
            }

            map.put("data", list);
            map.put("page", page);
            result.setData(map);
            return result;
        } catch (Exception e) {
            logger.error("PaymentmentServiceImpl.getListByPage error : {}", e);
            throw new BusinessException("查询失败!");
        }
    }

    /**
     * @param customerOrderId 客户订单id
     * @param score           是否使用积分 0:未使用 1:使用
     * @return Result<Object>
     * @Title: 支付初始化方法
     * @Description: 支付初始化方法
     */
    @Override
    public Result<Object> payInit(long customerOrderId, String payType, Integer score) {
        logger.info("PaymentmentServiceImpl.payInit param : {}, payType : {}, score : {}.", customerOrderId, payType, score);
        Date currentDate = new Date();
        Result<Object> result = new Result<Object>(false);
        try {
            // 订单查询
            SOrder order = this.getOrderService().getUnpaidOrder(customerOrderId);
            SOrderPayment payment = new SOrderPayment();
            payment.setOrderId(customerOrderId);
            payment.setPayType(payType);
            // payment.setActualCost(order.getOrderCost());
            payment.setActualCost(order.getActualCost());
            payment.setPayAccount("");
            payment.setPayReceipt("");
            payment.setUpdateTime(currentDate);
            payment.setCreateTime(currentDate);
            this.getSOrderPaymentMapper().insertSelective(payment);

            payment.setPayAccount(order.getOrderCode() + "A" + payment.getId());
            this.getSOrderPaymentMapper().updateByPrimaryKey(payment);

            if (score == 1) {
                logger.info("PaymentmentServiceImpl.payInit param : {}, payType : {}, score : {}, 使用积分.", customerOrderId, payType, score);
                BigDecimal amount = this.getBScoresTurnoverService().getNotUsedScores(payment.getId(), customerOrderId);
                logger.info("PaymentmentServiceImpl.payInit param : {}, payType : {}, score : {}, 查询可用积分兑换金额amount : {}.", customerOrderId, payType, score, amount);
                if (amount != null && amount.compareTo(BigDecimal.ZERO) == 1) {
                    SOrderPayment paymentScores = new SOrderPayment();
                    paymentScores.setActualCost(amount);
                    paymentScores.setComment("积分抵扣金额");
                    paymentScores.setUserId(order.getUserId());
                    paymentScores.setPayType(PayTypeEnum.ScorePay.getValue());
                    paymentScores.setOrderId(customerOrderId);
                    paymentScores.setCreateTime(currentDate);
                    paymentScores.setUpdateTime(currentDate);
                    paymentScores.setPayAccount("");
                    paymentScores.setPayReceipt("");
                    logger.info("PaymentmentServiceImpl.payInit param : {}, payType : {}, score : {}, 积分抵扣金额写入orderPayment: {}.", customerOrderId, payType, score, paymentScores);
                    this.getSOrderPaymentMapper().insertSelective(paymentScores);

                    payment.setActualCost(order.getActualCost().subtract(amount).setScale(2));
                }
            }
			
			/*Long id = this.getsOrderPaymentViewMapper().selectLastId();
			if(id == null){
				id = 1L;
			}*/
            Charge charge = this.creatCharge(order, payment.getActualCost(), payType, "A" + payment.getId());
            result.setSuccess(true);
            result.setMessage("支付申请已提交.");
            result.setData(charge);
        } catch (Exception e) {
            logger.error("PaymentmentServiceImpl.payInit error : {}", e);
            throw new BusinessException("支付失败.");
        }
        return result;
    }

    /**
     * fill pin++ Charge
     *
     * @param order
     * @param cost
     * @param channel 渠道
     * @param flag    orderno后缀
     * @return
     * @throws ChannelException
     * @throws APIException
     * @throws AuthenticationException
     * @throws InvalidRequestException
     * @throws APIConnectionException
     */
    private Charge creatCharge(SOrder order, BigDecimal cost, String channel, String flag) throws Exception {
        logger.info("PaymentmentServiceImpl.createCharge param : {}, {}, {}", order.getId(), cost, channel);
        Charge charge = null;
        Pingpp.apiKey = HYCUtils.getConstantPropertiesLoader().getProperty(PingPPConstant.PINGPP_API_AECRET_KEY);
        Map<String, Object> chargeMap = new HashMap<String, Object>();
        cost = cost.multiply(BigDecimal.valueOf(100));

        chargeMap.put("amount", cost.intValue());
        chargeMap.put("currency", "cny");
        chargeMap.put("subject", "订单支付");
        chargeMap.put("body", "支付订单号为：" + order.getOrderCode());

        // String orderno=order.getOrderCode() + RandomUtils.bitInteger(ORDER_LENGTH);
        String orderno = order.getOrderCode() + flag;
        chargeMap.put("order_no", orderno);
        chargeMap.put("channel", channel);
        //chargeMap.put("client_ip", "127.0.0.1");
        chargeMap.put("client_ip", HttpUtils.getUserIp());
        Map<String, String> app = new HashMap<String, String>();
        app.put("id", HYCUtils.getConstantPropertiesLoader().getProperty(PingPPConstant.PINGPP_KEY));
        //公众号支付
        if (channel == PingPPChannelEnum.WX_PUB.getValue()) {
            Map<String, String> extramap = new HashMap<String, String>();
            // extra的参数根据文档: https://pingxx.com/document/api#api-c-new
            extramap.put("open_id", HYCUtils.getUserWeixinOpenId());
            chargeMap.put("extra", extramap);
        } else if (channel == PingPPChannelEnum.YEEPAY_WAP.getValue()) {
            Map<String, String> extramap = createYeepayExtraMap();
            chargeMap.put("extra", extramap);
        }
        chargeMap.put("app", app);
        charge = Charge.create(chargeMap);
        logger.info("PaymentmentServiceImpl.createCharge return : {}", charge);
        return charge;
    }

    /**
     * 创建易宝支付 参数
     *
     * @return
     */
    private Map<String, String> createYeepayExtraMap() throws Exception {
        Map<String, String> extramap = new HashMap<String, String>();
        // extra的参数根据文档: https://pingxx.com/document/api#api-c-new
        extramap.put("product_category", "20");
        extramap.put("identity_id", HYCUtils.getYeepayId());
        extramap.put("identity_type", "2");//0IMEI  1MAC 地址 2用户ID 3用户Email 4用户手机号  5用户身份证号 6用户纸质订单协议号
        extramap.put("terminal_type", "2"); // 0:IMEI, 1:MAC, 2:UUID, 3:other，
        SUserDevices userDevices = getUserDeviceService().getCurrentUserLastDevice();
        if (null != userDevices && StringUtils.isNotEmpty(userDevices.getUuid())) {
            extramap.put("terminal_id", userDevices.getUuid());
        } else {
            extramap.put("terminal_id", "00000000-0000-0000-0000-000000000000");
        }
        //TODO: 修改为获取 用户agent , result_url
        extramap.put("user_ua", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36");
        extramap.put("result_url", "http://www.huiyunche.cn/driver");
        logger.info("pay, yeepay, create extramap: {}", JSON.toJSONString(extramap));
        return extramap;
    }

    /**
     * 根据客户订单id 查询支付记录
     *
     * @param orderId
     * @return
     */
    @Override
    public QueryScoresVo getOrderCost(Long orderId) {
        logger.info("select order cost list params orderId : {}.", orderId);
        QueryScoresVo vo = new QueryScoresVo();
        vo.setAmount(BigDecimal.ZERO);
        vo.setActualPay(BigDecimal.ZERO);
        try {
            SOrderPaymentExample example = new SOrderPaymentExample();
            example.createCriteria().andOrderIdEqualTo(orderId);
            List<SOrderPayment> payments = this.getSOrderPaymentMapper().selectByExample(example);
            for (SOrderPayment sOrderPayment : payments) {
                if (sOrderPayment.getPayType().equals(PayTypeEnum.ScorePay.getValue())) {
                    vo.setAmount(sOrderPayment.getActualCost());
                } else {
                    vo.setActualPay(sOrderPayment.getActualCost());
                }
            }
        } catch (Exception e) {
            logger.info("select order cost list params orderId : {}, error : {}.", orderId, e);
            throw new BusinessException("根据客户订单ID查询支付记录异常");
        }
        return vo;
    }

    public SOrderPaymentMapper getSOrderPaymentMapper() {
        return this.sOrderPaymentMapper;
    }

    public SOrderPaymentViewMapper getsOrderPaymentViewMapper() {
        return this.sOrderPaymentViewMapper;
    }

    public SOrderService getOrderService() {
        return this.orderService;
    }

    public UserService getUserService() {
        return this.userService;
    }

    public OrderStatusLogService getOrderStatusLogService() {
        return this.orderStatusLogService;
    }

    public UserDeviceService getUserDeviceService() {
        return userDeviceService;
    }
}